/*
 * Copyright (C) 1997-2001 Id Software, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * =======================================================================
 *
 * Main header file for the client
 *
 * =======================================================================
 */  

#ifndef SV_SERVER_H
#define SV_SERVER_H

#include "../../common/header/common.h"
#include "../../game/header/game.h"

#define MAX_MASTERS 8 
#define LATENCY_COUNTS  16
#define RATE_MESSAGES   10

/* MAX_CHALLENGES is made large to prevent a denial 
   of service attack that could cycle all of them 
   out before legitimate users connected */
#define MAX_CHALLENGES  1024

#define SV_OUTPUTBUF_LENGTH ( MAX_MSGLEN - 16 )

#define EDICT_NUM( n ) ( (edict_t *) ( (byte *) ge->edicts + ge->edict_size * ( n ) ) )
#define NUM_FOR_EDICT( e ) ( ( (byte *) ( e ) - (byte *) ge->edicts ) / ge->edict_size )

typedef enum
{
	ss_dead,            /* no map loaded */
	ss_loading,         /* spawning level edicts */
	ss_game,            /* actively running */
	ss_cinematic,
	ss_demo,
	ss_pic
} server_state_t;

typedef struct
{
	server_state_t state;           /* precache commands are only valid during load */

	qboolean attractloop;           /* running cinematics and demos for the local system only */
	qboolean loadgame;              /* client begins should reuse existing entity */

	unsigned time;                  /* always sv.framenum * 100 msec */
	int framenum;

	char name [ MAX_QPATH ];        /* map name, or cinematic name */
	struct cmodel_s     *models [ MAX_MODELS ];

	char configstrings [ MAX_CONFIGSTRINGS ] [ MAX_QPATH ];
	entity_state_t baselines [ MAX_EDICTS ];

	/* the multicast buffer is used to send a message to a set of clients 
	   it is only used to marshall data until SV_Multicast is called */
	sizebuf_t multicast;
	byte multicast_buf [ MAX_MSGLEN ];

	/* demo server information */
	FILE        *demofile;
	qboolean timedemo; /* don't time sync */
} server_t;

typedef enum
{
	cs_free,        /* can be reused for a new connection */
	cs_zombie,      /* client has been disconnected, but don't reuse */
					/* connection for a couple seconds */
	cs_connected,   /* has been assigned to a client_t, but not in game yet */
	cs_spawned      /* client is fully in game */
} client_state_t;

typedef struct
{
	int areabytes;
	byte areabits [ MAX_MAP_AREAS / 8 ];    /* portalarea visibility bits */
	player_state_t ps;
	int num_entities;
	int first_entity;                       /* into the circular sv_packet_entities[] */
	int senttime;                           /* for ping calculations */
} client_frame_t;

typedef struct client_s
{
	client_state_t state;

	char userinfo [ MAX_INFO_STRING ];  /* name, etc */

	int lastframe;                      /* for delta compression */
	usercmd_t lastcmd;                  /* for filling in big drops */

	int commandMsec;                    /* every seconds this is reset, if user */
										/* commands exhaust it, assume time cheating */

	int frame_latency [ LATENCY_COUNTS ];
	int ping;

	int message_size [ RATE_MESSAGES ]; /* used to rate drop packets */
	int rate;
	int surpressCount;                  /* number of messages rate supressed */

	edict_t         *edict;             /* EDICT_NUM(clientnum+1) */
	char name [ 32 ];                   /* extracted from userinfo, high bits masked */
	int messagelevel;                   /* for filtering printed messages */

	/* The datagram is written to by sound calls, prints, temp ents, etc. 
	   It can be harmlessly overflowed. */
	sizebuf_t datagram;
	byte datagram_buf [ MAX_MSGLEN ];

	client_frame_t frames [ UPDATE_BACKUP ];  /* updates can be delta'd from here */

	byte            *download;          /* file being downloaded */
	int downloadsize;                   /* total bytes (can't use EOF because of paks) */
	int downloadcount;                  /* bytes sent */

	int lastmessage;                    /* sv.framenum when packet was last received */
	int lastconnect;

	int challenge;                      /* challenge of this user, randomly generated */

	netchan_t netchan;
} client_t;

typedef struct
{
	netadr_t adr;
	int challenge;
	int time;
} challenge_t;

typedef struct
{
	qboolean initialized;               /* sv_init has completed */
	int realtime;                       /* always increasing, no clamping, etc */

	char mapcmd [ MAX_TOKEN_CHARS ];    /* ie: *intro.cin+base */

	int spawncount;                     /* incremented each server start */
										/* used to check late spawns */

	client_t    *clients;               /* [maxclients->value]; */
	int num_client_entities;            /* maxclients->value*UPDATE_BACKUP*MAX_PACKET_ENTITIES */
	int next_client_entities;           /* next client_entity to use */
	entity_state_t  *client_entities;   /* [num_client_entities] */

	int last_heartbeat;

	challenge_t challenges [ MAX_CHALLENGES ]; /* to prevent invalid IPs from connecting */

	/* serverrecord values */
	FILE        *demofile;
	sizebuf_t demo_multicast;
	byte demo_multicast_buf [ MAX_MSGLEN ];
} server_static_t;

extern netadr_t net_from;
extern sizebuf_t net_message;

extern netadr_t master_adr [ MAX_MASTERS ]; /* address of the master server */

extern server_static_t svs;                 /* persistant server info */
extern server_t sv;                         /* local server */

extern cvar_t      *sv_paused;
extern cvar_t      *maxclients;
extern cvar_t      *sv_noreload;            /* don't reload level state when reentering */
extern cvar_t      *sv_airaccelerate;       /* don't reload level state when reentering */
											/* development tool */
extern cvar_t      *sv_enforcetime;

extern client_t    *sv_client;
extern edict_t     *sv_player;

void SV_FinalMessage ( char *message, qboolean reconnect );
void SV_DropClient ( client_t *drop );

int SV_ModelIndex ( char *name );
int SV_SoundIndex ( char *name );
int SV_ImageIndex ( char *name );

void SV_WriteClientdataToMessage ( client_t *client, sizebuf_t *msg );

void SV_ExecuteUserCommand ( char *s );
void SV_InitOperatorCommands ( void );

void SV_SendServerinfo ( client_t *client );
void SV_UserinfoChanged ( client_t *cl );

void Master_Heartbeat ( void );
void Master_Packet ( void );

void SV_InitGame ( void );
void SV_Map ( qboolean attractloop, char *levelstring, qboolean loadgame );

void SV_PrepWorldFrame ( void );

typedef enum {RD_NONE, RD_CLIENT, RD_PACKET} redirect_t;

extern char sv_outputbuf [ SV_OUTPUTBUF_LENGTH ];

void SV_FlushRedirect ( int sv_redirected, char *outputbuf );

void SV_DemoCompleted ( void );
void SV_SendClientMessages ( void );

void SV_Multicast ( vec3_t origin, multicast_t to );
void SV_StartSound ( vec3_t origin, edict_t *entity, int channel, int soundindex, float volume, float attenuation, float timeofs );
void SV_ClientPrintf ( client_t *cl, int level, char *fmt, ... );
void SV_BroadcastPrintf ( int level, char *fmt, ... );
void SV_BroadcastCommand ( char *fmt, ... );

void SV_Nextserver ( void );
void SV_ExecuteClientMessage ( client_t *cl );

void SV_ReadLevelFile ( void );
void SV_Status_f ( void );

void SV_WriteFrameToClient ( client_t *client, sizebuf_t *msg );
void SV_RecordDemoMessage ( void );
void SV_BuildClientFrame ( client_t *client );

void SV_Error ( char *error, ... );

extern game_export_t   *ge;

void SV_InitGameProgs ( void );
void SV_ShutdownGameProgs ( void );
void SV_InitEdict ( edict_t *e );

/* server side savegame stuff */
void SV_WipeSavegame ( char *savename );
void SV_CopySaveGame ( char *src, char *dst );
void SV_WriteLevelFile ( void );
void SV_WriteServerFile ( qboolean autosave );
void SV_Loadgame_f ( void );
void SV_Savegame_f ( void );

/* high level object sorting to reduce interaction tests */
void SV_ClearWorld ( void );

/* called after the world model has been loaded, before linking any entities */
void SV_UnlinkEdict ( edict_t *ent );

/* call before removing an entity, and before trying to move one,
   so it doesn't clip against itself */
void SV_LinkEdict ( edict_t *ent );

/* Needs to be called any time an entity changes origin, mins, maxs,
   or solid.  Automatically unlinks if needed.
   sets ent->v.absmin and ent->v.absmax 
   sets ent->leafnums[] for pvs determination even if the entity is not solid */
int SV_AreaEdicts ( vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype );

int SV_PointContents ( vec3_t p );

trace_t SV_Trace ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask );

#endif

